home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 21
/
CU Amiga Magazine's Super CD-ROM 21 (1998)(EMAP Images)(GB)[!][issue 1998-04].iso
/
CUCD
/
Programming
/
PPCcforth
/
prims.c
< prev
next >
Wrap
C/C++ Source or Header
|
1985-12-27
|
11KB
|
486 lines
/*
* prims.c -- code for the primitive functions declared in forth.dict
*/
#include <stdio.h>
#include <ctype.h> /* used in "digit" */
#include "common.h"
#include "forth.h"
#include "prims.h" /* macro primitives */
/*
----------------------------------------------------
PRIMITIVE DEFINITIONS
----------------------------------------------------
*/
zbranch() /* add an offset (branch) if tos == 0 */
{
if(pop() == 0)
ip += mem[ip];
else
ip++; /* else skip over the offset */
}
ploop() /* (loop) -- loop control */
{
short index, limit;
index = rpop()+1;
if(index < (limit = rpop())) { /* if the new index < the limit */
rpush(limit); /* restore the limit */
rpush(index); /* and the index (incremented) */
branch(); /* and go back to the top of the loop */
}
else ip++; /* skip over the offset, and exit, having
popped the limit & index */
}
pploop() /* (+loop) -- almost the same */
{
short index, limit;
index = rpop()+pop(); /* get index & add increment */
if(index < (limit = rpop())) { /* if new index < limit */
rpush (limit); /* restore the limit */
rpush (index); /* restore the new index */
branch(); /* and branch back to the top */
}
else {
ip++; /* skip over branch offset */
}
}
pdo() /* (do): limit init -- [pushed to rstack] */
{
swap();
rpush (pop());
rpush (pop());
}
i() /* copy top of return stack to cstack */
{
int tmp;
tmp = rpop();
rpush(tmp);
push(tmp);
}
r() /* this must be a primitive as well as I because otherwise it
always returns its own address */
{
i();
}
digit() /* digit: c -- FALSE or [v TRUE] */
{
short c, base; /* C is ASCII char, convert to val. BASE is
used for range checking */
base = pop();
c = pop();
if (!isascii(c)) {
push (FALSE);
return;
}
/* lc -> UC if necessary */
if (islower(c)) c = toupper(c);
if (c < '0' || (c > '9' && c < 'A') || c > 'Z') {
push(FALSE); /* not a digit */
}
else { /* it is numeric or UC Alpha */
if (c >= 'A') c -= 7; /* put A-Z right after 0-9 */
c -= '0'; /* now c is 0..35 */
if (c >= base) {
push (FALSE); /* FALSE - not a digit */
}
else { /* OKAY: push value, then TRUE */
push (c);
push (TRUE);
}
}
}
pfind() /* WORD TOP -- xx FLAG, where TOP is NFA to start at;
WORD is the word to find; xx is PFA of found word;
yy is actual length of the word found;
FLAG is 1 if found. If not found, 0 alone is stacked. */
{
unsigned short worka, workb, workc, current, word, match;
current = pop ();
word = pop ();
while (current) { /* stop at end of dictionary */
if (!((mem[current] ^ mem[word]) & 0x3f)) {
/* match lengths & smudge */
worka = current + 1;/* point to the first letter */
workb = word + 1;
workc = mem[word]; /* workc gets count */
match = TRUE; /* initally true, for looping */
while (workc-- && match)
match = ((mem[worka++] & 0x7f) == (mem[workb++] & 0x7f));
if (match) { /* exited with match TRUE -- FOUND IT */
push (worka + 2); /* worka=LFA; push PFA */
push (mem[current]); /* push length byte */
push (TRUE); /* and TRUE flag */
return;
}
}
/* failed to match */
/* follow link field to next word */
current = mem[current + (mem[current] & 0x1f) + 1];
}
push (FALSE); /* current = 0; end of dict; not found */
}
enclose()
{
int delim, current, offset;
delim = pop();
current = pop();
push (current);
offset = -1;
current--;
encl1:
current++;
offset++;
if (mem[current] == delim) goto encl1;
push(offset);
if (mem[current] == NULL) {
offset++;
push (offset);
offset--;
push (offset);
return;
}
encl2:
current++;
offset++;
if (mem[current] == delim) goto encl4;
if (mem[current] != NULL) goto encl2;
/* mem[current] is null.. */
push (offset);
push (offset);
return;
encl4: /* found the trailing delimiter */
push (offset);
offset++;
push (offset);
return;
}
cmove() /* cmove: source dest number -- */
{
short source, dest, number, i;
number = pop();
dest = pop();
source = pop();
for ( ; number ; number-- ) mem[dest++] = mem[source++];
}
fill() /* fill: c dest number -- */
{
short dest, number, c;
number = pop();
dest = pop();
c = pop();
mem[dest] = c; /* always at least one */
if (number == 1) return; /* return if only one */
push (dest); /* else push dest as source of cmove */
push (dest + 1); /* dest+1 as dest of cmove */
push (number - 1); /* number-1 as number of cmove */
cmove();
}
ustar() /* u*: a b -- a*b.hi a*b.lo */
{
unsigned short a, b;
unsigned long c;
a = (unsigned short)pop();
b = (unsigned short)pop();
c = a * b;
/* (short) -1 is probably FFFF, which is just what we want */
push ((unsigned short)(c & (short) -1)); /* low word of product */
/* high word of product */
push ((short)((c >> (8*sizeof(short))) & (short) -1));
}
uslash() /* u/: NUM.LO NUM.HI DENOM -- REM QUOT */
{
unsigned short numhi, numlo, denom;
unsigned short quot, remainder; /* the longs below are to be sure the
intermediate computation is done
long; the results are short */
denom = pop();
numhi = pop();
numlo = pop();
quot = ((((unsigned long)numhi) << (8*sizeof(short)))
+ (unsigned long)numlo)
/ (unsigned long)denom;
remainder = ((((unsigned long)numhi) << (8*sizeof(short)))
+ (unsigned long)numlo)
% (unsigned long)denom;
push (remainder);
push (quot);
}
swap() /* swap: a b -- b a */
{
short a, b;
b = pop();
a = pop();
push (b);
push (a);
}
rot() /* rotate */
{
short a, b, c;
a = pop ();
b = pop ();
c = pop ();
push (b);
push (a);
push (c);
}
tfetch() /* 2@: addr -- mem[addr+1] mem[addr] */
{
unsigned short addr;
addr = pop();
push (mem[addr + 1]);
push (mem[addr]);
}
store() /* !: val addr -- <set mem[addr] = val> */
{
unsigned short tmp;
tmp = pop();
mem[tmp] = pop();
}
cstore() /* C!: val addr -- */
{
store();
}
tstore() /* 2!: val1 val2 addr --
mem[addr] = val2,
mem[addr+1] = val1 */
{
unsigned short tmp;
tmp = pop();
mem[tmp] = pop();
mem[tmp+1] = pop();
}
leave() /* set the index = the limit of a DO */
{
int tmp;
rpop(); /* discard old index */
tmp = rpop(); /* and push the limit as */
rpush(tmp); /* both the limit */
rpush(tmp); /* and the index */
}
dplus() /* D+: double-add */
{
short ahi, alo, bhi, blo;
long a, b;
bhi = pop();
blo = pop();
ahi = pop();
alo = pop();
a = ((long)ahi << (8*sizeof(short))) + (long)alo;
b = ((long)bhi << (8*sizeof(short))) + (long)blo;
a = a + b;
push ((unsigned short)(a & (short) -1)); /* sum lo */
push ((short)(a >> (8*sizeof(short)))); /* sum hi */
}
subtract() /* -: a b -- (a-b) */
{
int tmp;
tmp = pop();
push (pop() - tmp);
}
dsubtract() /* D-: double-subtract */
{
short ahi, alo, bhi, blo;
long a, b;
bhi = pop();
blo = pop();
ahi = pop();
alo = pop();
a = ((long)ahi << (8*sizeof(short))) + (long)alo;
b = ((long)bhi << (8*sizeof(short))) + (long)blo;
a = a - b;
push ((unsigned short)(a & (short) -1)); /* diff lo */
push ((short)(a >> (8*sizeof(short)))); /* diff hi */
}
dminus() /* DMINUS: negate a double number */
{
unsigned short ahi, alo;
long a;
ahi = pop();
alo = pop();
a = -(((long)ahi << (8*sizeof(short))) + (long)alo);
push ((unsigned short)(a & (short) -1)); /* -a lo */
push ((unsigned short)(a >> (8*sizeof(short)))); /* -a hi */
}
over() /* over: a b -- a b a */
{
short a, b;
b = pop();
a = pop();
push (a);
push (b);
push (a);
}
dup() /* dup: a -- a a */
{
short a;
a = pop();
push (a);
push (a);
}
tdup() /* 2dup: a b -- a b a b */
{
short a, b;
b = pop();
a = pop();
push (a);
push (b);
push (a);
push (b);
}
pstore() /* +!: val addr -- <add val to mem[addr]> */
{
short addr, val;
addr = pop();
val = pop();
mem[addr] += val;
}
toggle() /* toggle: addr bits -- <xor mem[addr]
with bits, store in mem[addr]> */
{
short bits, addr;
bits = pop();
addr = pop();
mem[addr] ^= bits;
}
less()
{
int tmp;
tmp = pop();
push (pop() < tmp);
}
pcold()
{
csp = INITS0; /* initialize values */
rsp = INITR0;
/* copy USER_DEFAULTS area into UP area */
push (USER_DEFAULTS); /* source */
push (UP); /* dest */
push (DEFS_SIZE); /* count */
cmove(); /* move! */
/* returns, executes ABORT */
}
prslw()
{
int buffer, flag, addr, i, temp;
int unwrittenflag = !TRUE;
long fpos, ftell();
char buf[1024]; /* holds data for xfer */
flag = pop();
buffer = pop();
addr = pop();
fpos = (long) (buffer * 1024);
/* extend if necessary */
if (fpos >= bfilesize) {
if (flag == 0) { /* write */
printf("Extending block file to %D bytes\n", fpos+1024);
/* the "2" below is the fseek magic number for "beyond end" */
fseek(blockfile, (fpos+1024) - bfilesize, 2);
bfilesize = ftell(blockfile);
}
else { /* reading unwritten data */
unwrittenflag = TRUE; /* will read all zeroes */
}
}
else {
/* note that "0" below is fseek magic number for "relative to
beginning-of-file" */
fseek(blockfile, fpos, 0); /* seek to destination */
}
if (flag) { /* read */
if (unwrittenflag) { /* not written yet */
for (i=0; i<1024; i++) mem[addr++] = 0; /* "read" nulls */
}
else { /* does exist */
if ((temp = fread (buf, sizeof(char), 1024, blockfile))
!= 1024) {
fprintf (stderr,
"File read error %d reading buffer %d\n",
temp, buffer);
errexit();
}
for (i=0; i<1024; i++) mem[addr++] = buf[i];
}
}
else { /* write */
for (i=0; i<1024; i++) buf[i] = mem[addr++];
if ((temp = fwrite (buf, sizeof(char), 1024, blockfile))
!= 1024) {
fprintf(stderr,
"File write error %d writing buffer %d\n",
temp, buffer);
errexit();
}
}
}
psave()
{
FILE *fp;
printf("\nSaving...");
fflush(stdout);
mem[SAVEDIP] = ip; /* save state */
mem[SAVEDSP] = csp;
mem[SAVEDRP] = rsp;
if ((fp = fopen(sfilename,"w")) == NULL) /* open for writing only */
errexit("Can't open core file %s for writing\n", sfilename);
if (fwrite(mem, sizeof(*mem), mem[0], fp) != mem[0])
errexit("Write error on %s\n",sfilename);
if (fclose(fp) == EOF)
errexit("Close error on %s\n",sfilename);
puts("Saved. Exit FORTH.");
exit(0);
}